package com.knowledge.plus.泛型.通配符;

import org.junit.Test;

import java.util.ArrayList;

/**
 * 上界通配符 <? extends T>，类型参数的范围是 T 和 T 的子类
 * 可以读，不能写。因为编译器不知道确切的类型是什么，所以不能保证类型安全
 *
 * @author TPF
 * @since 2023/7/27
 */
public class 上界通配符 {

    /**
     * <? extends T> 也是一个数据类型实参，它和 Number、String、Integer 一样都是一种实际的数据类型
     */
    public void genericTypeUsage() {
        // 在 ArrayList<? extends Number> 集合中，不能添加任何数据类型的对象，只能添加空值 null，因为 null 可以表示任何数据类型
        ArrayList<? extends Number> list01 = new ArrayList<Integer>();
        list01.add(null);   // 编译正确
        list01.set(1, null);  // 编译成功，但不建议这样使用

        // 可以读，不能写
        list01.get(0);
        // list01.add(new Integer(1));   // 编译错误
        // list01.add(new Float(1.0));   // 编译错误
        // list01.set(1, new Integer(2));    // 编译错误

        // ArrayList<Number> list02 = new ArrayList<Integer>();    // 编译错误
        ArrayList<Number> list02 = new ArrayList<>();
    }

    /**
     * ArrayList<Integer> 和 ArrayList<Number> 之间不存在继承关系
     * 引入上界通配符的概念后，我们便可以在逻辑上将 ArrayList<? extends Number> 看做是 ArrayList<Integer> 的父类，但实质上它们之间没有继承关系
     */
    @Test
    public void genericTypeTest() {
        // 创建一个 ArrayList<Integer> 集合
        ArrayList<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        integerList.add(2);
        // 将 ArrayList<Integer> 传入 printIntVal() 方法
        printIntVal(integerList);

        // 创建一个 ArrayList<Float> 集合
        ArrayList<Float> floatList = new ArrayList<>();
        floatList.add((float) 1.0);
        floatList.add((float) 2.0);
        // 将 ArrayList<Float> 传入 printIntVal() 方法
        printIntVal(floatList);
    }

    public static void printIntVal(ArrayList<? extends Number> list) {
        // 遍历传入的集合，并输出集合中的元素
        for (Number number : list) {
            if (number instanceof Integer) {
                System.out.print("Integer类型 = ");
            } else if (number instanceof Float) {
                System.out.print("Float类型 = ");
            }
            System.out.print(number.intValue() + "\t\t");
        }
        System.out.println();
    }

}
